# -*- coding: utf-8 -*-
import json
import logging

from common.recharge.model import *
from common.recharge import db as recharge_db
from common.pay.handler import pay_after_recharge

from common.account.db.account import get_account
from common.transaction.db import add_system_award_transaction

from common.utils.tz import utc_to_local
from common.utils import exceptions as err
from common.system_recharge.db import create_system_trans
from common.utils import id_generator, EnhencedEncoder

from future.utils import raise_with_traceback

_LOGGER = logging.getLogger('pay')

_DEFAULT_PAGE_SIZE = 20


def _check_recharger_info(recharge_type, recharger_info):
    # rule = RECHARGER_RULE.get(recharge_type)
    # if not rule:
    #     return False
    #
    # rule_dict = RECHARGER_RULE[recharge_type]
    # for k,v in rule_dict.items():
    #     if k not in recharger_info:
    #         return False
    #     if not isinstance(recharger_info[k], v):
    #         try:
    #             recharger_info[k] = v(recharger_info[k])
    #         except:
    #             return False
    return True


def _check_rechargee_info(recharge_type, recharger_info):
    return True


def _calc_extra_award(amount):
    # for conf in EXTRA_AMOUNT:
    #     if conf[0] <= amount <= conf[1]:
    #         return conf[2]
    if amount >= 5:
        return amount * 0.02
    return 0


def apply_recharge(user_id, recharge_type, recharger_info, rechargee_info):
    """
    call by client
    """
    account = get_account(user_id)
    if not account:
        raise err.ParamError('uid {} invalid'.format(user_id))
    if not _check_recharger_info(recharge_type, recharger_info):
        raise err.ParamError(u'recharger info invalid')
    if not _check_rechargee_info(recharge_type, rechargee_info):
        raise err.ParamError(u'rechargee info invalid')

    try:
        return recharge_db.submit_apply(user_id, recharge_type, recharger_info, rechargee_info)
    except err.DataError as e:
        return
    except Exception as e:
        raise err.ServerError('apply exception')


def get_user_applys(user_id, page, size):
    limit = 0 if not size else size
    if not size and page > 0:
        limit = _DEFAULT_PAGE_SIZE
    offset = 0 if not page else (page - 1) * limit

    records = recharge_db.get_applys(user_id, limit, offset)

    r_list = []
    for record in records:
        r_list.append({
            'id': record.id,
            'type': record.recharge_type,
            'rechargee': json.loads(record.rechargee_info),
            'created_at': utc_to_local(
                record.created_at).strftime('%Y-%m-%d %H:%M'),
            'price': record.pay_amount,
            'status': record.status,
            'updated_at': utc_to_local(
                record.updated_at).strftime('%Y-%m-%d %H:%M') if record.status == 2 else '-',
        })

    return r_list


def finish_apply(admin_id, apply_id, pay_amount, trans_id=None):
    pay = recharge_db.finish_apply(admin_id, apply_id, pay_amount, trans_id)
    if not pay:
        raise err.DataError()
    # 以后统一用控制台配置，去掉旧的写死的"充值加奖"
    # extra_award = _calc_extra_award(pay_amount)
    # if extra_award:
    #     add_system_award_transaction(pay.user_id, extra_award, u'充值加奖')
    return pay


def submit_alipay_trans(third_id, remark_id, trans_amount, pay_time, payer_name=None):
    """
    callback by alipay monitor
    """
    trans = recharge_db.new_alipay_trans(third_id, remark_id, trans_amount, pay_time)
    if remark_id.isdigit() and get_account(remark_id):
        # valid trans, apply recharge
        user_id = int(remark_id)
        recharger_info = {
            'alipay_order_id': third_id,
            'name': payer_name,
            'uid': user_id,
        }
        rechargee_info = {}
        _LOGGER.info('submit_alipay_trans, submit %s, %s, %s', third_id, user_id, trans_amount)
        try:
            recharge_apply = recharge_db.submit_apply(user_id, RECHARGE_TYPE.ALIPAY, recharger_info, rechargee_info)
            # do recharge
            pay = finish_apply(0, recharge_apply.id, trans_amount, trans_id=trans.id)
            try:
                pay_after_recharge(pay)
            except Exception as e:
                _LOGGER.exception('submit_alipay_trans, pay_after_recharge of pay[%s] exception.(%s)', pay.id, e)
        except err.DataError as e:
            _LOGGER.warn('recharge submit_alipay_trans, apply exists, skip')
            return
        except Exception as e:
            _LOGGER.warn('recharge submit_alipay_trans, error, %s', e)


def check_alipay_apply():
    """
    cronjob to call
    """
    applied_items = recharge_db.fetch_applied_alipay()
    for item in applied_items:
        apply_id = item.id
        third_id = item.third_id
        trans = recharge_db.fetch_trans_by_third_id(third_id)
        if trans:
            _LOGGER.info('check_alipay_apply, found trans %s for %s', third_id, apply_id)
            pay = finish_apply(0, apply_id, trans.trans_amount, trans_id=trans.id)
            try:
                pay_after_recharge(pay)
            except Exception as e:
                _LOGGER.exception('check_alipay_apply, pay_after_recharge of pay[%s] exception.(%s)', pay.id, e)
        else:
            _LOGGER.info('check_alipay_apply, not found trans %s for %s', third_id, apply_id)


def finish_wechat_apply(user_id, pay_id, amount, agency_id):
    _LOGGER.info("finish_wechat_apply {} {} {} {}".format(user_id, pay_id, amount, agency_id))

    recharge = RechargeApply.query.with_for_update().filter(RechargeApply.pay_id == pay_id).first()
    account = get_account(user_id, use_cache=True)
    if not account or user_id != recharge.user_id:
        raise err.ParamError('no account or user_id error')
    if not recharge:
        # 充值
        _LOGGER.info("recharge apply finish_apply,recharge not exists")
        raise err.ParamError('no recharge')
    if recharge.status == RECHARGE_STATUS.ONGOING:
        pay = finish_apply(None, recharge.id, float(amount))
        try:
            pay_after_recharge(pay)
        except Exception as e:
            _LOGGER.exception('admin single recharge, pay_after_recharge of pay[%s] exception.(%s)', pay.id, e)
    else:
        if amount > 0:
            raise err.ParamError('amount must gt 0')
        note = '{} wechat apply adjust amount'.format(pay_id)
        operator = 'agency_id {}'.format(agency_id)
        trans_id = id_generator.generate_long_id('transaction')
        params = [dict(user_id=user_id, user_name=account.user_name, amount=amount)]
        create_system_trans(trans_id, params, operator, note, admin_id=None)
